using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Jitter.LinearMath;
using CrystalCore.Libs;

namespace CrystalCore.Mapping
{
    [Serializable]
    public struct MazePosition : IEquatable<MazePosition>, IEqualityComparer<MazePosition>
    {
        public int X;        
        public int Z;
        public int Level;

        public MazePosition(int x, int z, int Level = 0)
        {
            this.X = x;
            this.Z = z;
            this.Level = Level;
        }

        public Vector3 CenterCell
        {
           get 
            {
                return ToVector3(Globals.CellSize) + (Globals.CellSize / 2f);
            }
        }

        /// <summary>
        /// Converts to a Vector3
        /// </summary>
        /// <param name="multipler">The Scale Factor E.g. GLobals.CellSize</param>
        /// <returns></returns>
        public Vector3 ToVector3(Vector3 multipler)
        {
            return new Vector3(X * multipler.X, multipler.Y == 0 ? 0 : 1, Z * multipler.Z);
        }
        public JVector ToJVector(Vector3 multipler)
        {
            return Converter.ConvertVect(ToVector3(multipler));
        }

        public static MazePosition FromVector3(Vector3 source, Vector3 divisor)
        {
            MazePosition temp = new MazePosition();
            temp.X = (int)(source.X / divisor.X);
            temp.Level = (int)(source.Y / divisor.Y);
            temp.Z = (int)(source.Z / divisor.Z);
            return temp;
        }

        //Implicits and Statics
        public static MazePosition operator +(MazePosition one, MazePosition two)
        {
            return new MazePosition(one.X + two.X, one.Level, one.Z + two.Z);
        }
        public static MazePosition operator +(MazePosition one)
        {
            return new MazePosition(Math.Abs(one.X), Math.Abs(one.Level), Math.Abs(one.Z));
        }

        public static MazePosition operator -(MazePosition one, MazePosition two)
        {
            return new MazePosition(one.X - two.X, one.Level, one.Z - two.Z);
        }
        public static MazePosition operator -(MazePosition one)
        {
            return new MazePosition(Math.Abs(one.X) * -1, Math.Abs(one.Z) * -1);
        }

        public static bool operator ==(MazePosition one, MazePosition two)
        {
            return (one.X == two.X) && (one.Z == two.Z) && (one.Level == two.Level);
        }
        public static bool operator !=(MazePosition one, MazePosition two)
        {
            return (one.X != two.X) && (one.Z != two.Z) && (one.Level != two.Level);
        }

        public override string ToString()
        {
            return String.Format("X:{0}, Z:{1} L:{2}", this.X, this.Z, this.Level);
        }
        
        public static MazePosition Zero
        {
            get { return new MazePosition(0, 1, 0); }
        }
        public static MazePosition One
        {
            get {return new MazePosition(1, 1, 1);}
        }

        //Equality
        public override bool Equals(object obj)
        {
            if (obj is MazePosition)
                return Equals((MazePosition)obj);
            else
                return false;
        }
        public bool Equals(MazePosition other)
        {
            return (other.X == this.X) && (other.Z == this.Z) && (other.Level == this.Level);
        }        
        public bool Equals(MazePosition x, MazePosition y)
        {
            return (x.X == y.X) && (x.Z == y.Z) && (x.Level == y.Level);
        }

        public override int GetHashCode()
        {
            return GetHashCode(this);
        }
        public int GetHashCode(MazePosition obj)
        {
            int XHash = X.GetHashCode();
            int YHash = Z.GetHashCode();
            int Levelhash = Level.GetHashCode();

            return XHash ^ YHash ^ Levelhash;
        }
    }
}
